﻿
using Microsoft.Office.Interop.Word;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;

namespace OfficeMiddlewareCore
{


    /// <summary>
    /// Websocket 通讯Dto
    /// </summary>
    public class WsDto : IDisposable
    {
        // 判断文件是否打开
        [DllImport("kernel32.dll")]
        public static extern IntPtr _lopen(string lpPathName, int iReadWrite);

        // 关闭文件句柄
        [DllImport("kernel32.dll")]
        public static extern bool CloseHandle(IntPtr hObject);


        /// <summary>
        /// 事务Id
        /// </summary>
        public string Id { get; set; }

        /// <summary>
        /// 文件版本
        /// </summary>
        public int FileVersion { get; set; }

        /// <summary>
        /// 操作类型,  
        /// 新建正文 = 0, 
        /// 处理正文 = 1, 
        /// 查看正文 = 2, 
        /// 清稿 = 3, 
        /// 合成格式 = 4, 
        /// 文件是否存在 = 5,
        /// 文件是否打开 = 6, 
        /// 下载文件 = 7, 
        /// 打开Excel文件 = 8
        /// </summary>
        public OptType? OptType { get; set; }

        /// <summary>
        /// 正文路径
        /// </summary>
        public string FilePath { get; set; }

        /// <summary>
        /// 正文路径（多个正文)
        /// </summary>
        public string[] FilePathExt { get; set; }

        /// <summary>
        /// 红头路径(合并功能用)
        /// </summary>
        public string RedPath { get; set; }

        /// <summary>
        /// 版记路径(合并功能用)
        /// </summary>
        public string VerPath { get; set; }

        /// <summary>
        /// 打开模式 编辑模式打开=0,  只读模式打开=1
        /// </summary>
        public OpenType OpenType { get; set; }

        /// <summary>
        /// 模板中需要替换的参数,传标准json字符串
        /// </summary>
        public string Params { get; set; }

        /// <summary>
        /// 用户信息
        /// </summary>
        public string User { get; set; }

        /// <summary>
        /// 文档id，如果请求没有传 FileName,将作为下载文件的文件名
        /// </summary>
        public string DocCode { get; set; }

        /// <summary>
        /// 文件版本
        /// </summary>
        public int DocVer { get; set; }

        /// <summary>
        /// 是否复制页眉
        /// </summary>
        public bool CopyHeader { get; set; }
        /// <summary>
        /// 是否强制打开,忽略当前文档打开状态
        /// </summary>
        public bool IsForce { get; set; } = false;


        public string SessionId { get; set; }
        public string Token { get; set; }

        /// <summary>
        /// 上传文件路径，传空字符串或null的话，word关闭后将不会上传文件（也不会删除）
        /// 如果传了上传路径，，在word关闭后将word上传到uploadPath 地址，上传成功后删除本地文件
        /// </summary>
        public string UploadPath { get; set; }

        /// <summary>
        /// 文件名,下载文件后，存在本地的文件名，传空或null值，用DocCode命名
        /// </summary>
        public string FileName { get; set; }

        /// <summary>
        /// 下载到本地指定文件夹，如果不传，默认是系统临时文件夹
        /// </summary>
        public string FileDirectory { get; set; }

        public bool IsReadOnly { get => OpenType == OpenType.只读模式打开; }

        /// <summary>
        /// 备份通知请求路径
        /// </summary>
        public string BackupPath { get; set; }

        public Dictionary<string, string> GetReplaceDic()
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            if (!string.IsNullOrWhiteSpace(Params))
            {
                try
                {
                    result = JsonConvert.DeserializeObject<Dictionary<string, string>>(Params);
                }
                catch (Exception ex)
                {
                    LogHelper.Error("序列化参数错误", ex);
                }
            }
            return result;
        }
        public const string BaseFolder = "C:\\OAWordDocs\\{0}";
        public const string BackupFolder = "C:\\OAWordDocs\\{0}\\backup";

        /// <summary>
        /// 获取下载保存目录
        /// </summary>
        private string GetDownloadDirectory()
        {
            var path = string.Format(BaseFolder, User);
            if (OptType == OfficeMiddlewareCore.OptType.下载文件)
            {
                path = FileDirectory;
            }
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            return path;
        }
        private Core _coreInstance;
        public Core CoreInstance
        {
            get
            {
                if (_coreInstance == null) _coreInstance = Core.Create(this);
                return _coreInstance;
            }
        }


        public bool CheckValid()
        {
            var desc = new DESService("F6C9C524");

            try
            {
                if (desc.DESDeCode(Token) != "OAWordOper")
                {
                    SendMessage(CoreResponseStatus.Token校验失败);
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex.Message, ex);
                SendMessage(CoreResponseStatus.Token校验失败);
                return false;
            }
            return true;
        }
        private string _localFileName;
        public string LocalFileName
        {
            get
            {
                if (OptType == OfficeMiddlewareCore.OptType.检测Office安装情况 ||
                    OptType == OfficeMiddlewareCore.OptType.查看版本 ||
                    OptType == OfficeMiddlewareCore.OptType.打开文件夹)
                {
                    return string.Empty;
                }
                if (_localFileName == null && !string.IsNullOrWhiteSpace(DocCode))
                {
                    _localFileName = GetFileInfo().FullName;
                }
                return _localFileName;
            }
            set => _localFileName = value;
        }
        /// <summary>
        /// 执行
        /// </summary>
        public void Execute()
        {
            if (OptType == OfficeMiddlewareCore.OptType.文件是否打开)
            {
                SendMessage(CoreResponseStatus.操作成功, IsOpen() ? 1 : 0);
                return;
            }
            if (OptType == OfficeMiddlewareCore.OptType.文件是否存在)
            {
                SendMessage(CoreResponseStatus.操作成功, IsExists() ? 1 : 0);
                return;
            }
            if (OptType == OfficeMiddlewareCore.OptType.检测Office安装情况)
            {
                var hasOffice = Type.GetTypeFromProgID("Word.Application") != null;
                RegistryKey wpsLibrary = Registry.CurrentUser.OpenSubKey(@"Software\Kingsoft\Office\6.0\common");
                var hasWps = wpsLibrary != null && wpsLibrary.GetValue("InstallRoot") != null;
                var val = 0;
                if (hasOffice && hasWps)
                {
                    val = 3;
                }
                else if (hasWps)
                {
                    val = 2;
                }
                else if (hasOffice)
                {
                    val = 1;
                }
                SendMessage(CoreResponseStatus.操作成功, val);

                return;
            }
            if (IsOpen())
            {
                SendMessage(CoreResponseStatus.文件正在编辑);
                return;
            }
            if (OptType == OfficeMiddlewareCore.OptType.下载文件)
            {
                DownloadFile();
                _word = CoreInstance.MergeWord();

                SendMessage(CoreResponseStatus.操作成功);
                return;
            }

            var version = GetDocVersion();
            if (version <= FileVersion)
            {
                if (version > 0)
                {
                    BackupFile(version);
                }
                //下载文件失败
                //if (!DownloadFile())
                //{
                //    SendMessage(CoreResponseStatus.请求下载文件失败);
                //    return;
                //}
            }
            else
            {
                FileVersion = version;
            }

            if (!File.Exists(LocalFileName))
            {
                //下载文件失败
                if (!DownloadFile())
                {
                    SendMessage(CoreResponseStatus.请求下载文件失败);
                    return;
                }
            }

            switch (OptType)
            {
                case OfficeMiddlewareCore.OptType.新建正文:
                case OfficeMiddlewareCore.OptType.处理正文:
                    _word = CoreInstance.NewWord();
                    SendMessage(CoreResponseStatus.操作成功);
                    Upload();
                    break;
                case OfficeMiddlewareCore.OptType.查看留痕正文:
                    _word = CoreInstance.Review(true);
                    _word.Item1.Activate();

                    SendMessage(CoreResponseStatus.操作成功);
                    // _word.Item1.DocumentBeforeClose += Review_DocumentBeforeClose;
                    break;
                case OfficeMiddlewareCore.OptType.查看正文:
                    _word = CoreInstance.Review();
                    _word.Item1.Activate();
                    SendMessage(CoreResponseStatus.操作成功);
                    //  _word.Item1.DocumentBeforeClose += Review_DocumentBeforeClose;
                    break;
                case OfficeMiddlewareCore.OptType.打开文档:
                    CoreInstance.OpenWord();
                    SendMessage(CoreResponseStatus.操作成功);


                    break;
                case OfficeMiddlewareCore.OptType.清稿:
                    _word = CoreInstance.Clean();
                    SendMessage(CoreResponseStatus.操作成功);


                    Upload();
                    break;

                case OfficeMiddlewareCore.OptType.合成格式:
                    _word = CoreInstance.MergeWord();
                    SendMessage(CoreResponseStatus.操作成功);
                    Upload();
                    break;
                case OfficeMiddlewareCore.OptType.打开Excel:
                    CoreInstance.OpenExcel(success =>
                    {
                        UploadFile(LocalFileName);
                    });
                    SendMessage(CoreResponseStatus.操作成功);
                    break;
                //case OptType.查看版本:
                //    var ver = Assembly.GetExecutingAssembly().GetName().Version.ToString();
                //    SendMessage(CoreResponseStatus.操作成功, ver);
                //    break;
                default:
                    break;
            }

        }

        private void Review_DocumentBeforeClose(Document Doc, ref bool Cancel)
        {
            ThreadPool.QueueUserWorkItem(state =>
            {
                var file = state.ToString();
                DeleteFile(file);
            }, Doc.FullName);
        }

        public void BackupFile(int? version = null, string backFileName = null)
        {
            var dir = GetBackupFolder();
            var destFilePath = Path.Combine(dir, GetFileName(version ?? FileVersion, true));
            var sourceFilePath = backFileName;
            if (string.IsNullOrWhiteSpace(sourceFilePath))
            {
                sourceFilePath = Path.Combine(GetDownloadDirectory(), GetFileName(version ?? FileVersion));
            }
            if (!File.Exists(sourceFilePath))
            {
                return;
            }
            File.Copy(sourceFilePath, destFilePath, true);
            try
            {
                File.Delete(sourceFilePath);
            }
            catch (Exception ex)
            {
                SendMessage(CoreResponseStatus.文件本地已打开);
            }
            try
            {
                HttpHelper.Instance.NotificationBackup($"{BackupPath}?docCode={DocCode}", SessionId);
                SendMessage(CoreResponseStatus.备份文件成功);

            }
            catch (Exception)
            {
                SendMessage(CoreResponseStatus.备份文件通知服务器失败);
            }
        }

        public string GetBackupFolder()
        {
            var dir = string.Format(BackupFolder, User);
            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
            return dir;
        }
        public string GetRedFilePath()
        {
            var fileInfo = GetFileInfo();
            return Path.Combine(fileInfo.DirectoryName, "red_" + fileInfo.Name);
        }

        public string GetVerFilePath()
        {
            var fileInfo = GetFileInfo();
            return Path.Combine(fileInfo.DirectoryName, "ver" + fileInfo.Name);
        }

        public List<string> FilePathExts { get; set; } = new List<string>();

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <returns></returns>
        public bool DownloadFile()
        {
            var fileInfo = GetFileInfo();
            try
            {
                if (OptType == OfficeMiddlewareCore.OptType.合成格式 || OptType == OfficeMiddlewareCore.OptType.下载文件)
                {
                    if (FilePathExt != null && FilePathExt.Length > 0)
                    {
                        for (int i = 0; i < FilePathExt.Length; i++)
                        {
                            var filePath = Path.Combine(fileInfo.DirectoryName, (i == 0 ? "" : (i + "_")) + fileInfo.Name);
                            FilePathExts.Add(filePath);
                            HttpHelper.Instance.Download(FilePathExt[i], filePath, SessionId);
                        }
                    }
                    else
                    {
                        HttpHelper.Instance.Download(FilePath, fileInfo.FullName, SessionId);
                    }
                    HttpHelper.Instance.Download(VerPath, GetVerFilePath(), SessionId);
                    HttpHelper.Instance.Download(RedPath, GetRedFilePath(), SessionId);
                }
                else
                {
                    HttpHelper.Instance.Download(FilePath, fileInfo.FullName, SessionId);
                    LocalFileName = fileInfo.FullName;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error("下载文件 " + ex.Message, ex);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 发送消息给客户端
        /// </summary>
        public void SendMessage(CoreResponseStatus status, object data = null)
            => WebSocketResponse.Create(status, this, data);

        public string GetFileName(int? version = null, bool timestamp = false)
        {
            var file = FilePath;
            if (FilePathExt != null && FilePathExt.Length > 0) file = FilePathExt[0];
            var fileName = FileName;
            if (string.IsNullOrEmpty(fileName))
            {
                fileName = $"{DocCode}_{version ?? FileVersion}{(timestamp ? DateTime.Now.ToString("_yyyyMMddHHmmssfff") : "")}.{GetExt(file)}";
            }

            return fileName;
        }
        string GetExt(string filePath)
        {
            var arr = filePath.Split('.');
            if (arr.Length > 1)
            {
                return arr[arr.Length - 1];
            }
            else
            {
                return string.Empty;
            }
        }
        /// <summary>
        /// 获取文件信息
        /// </summary>
        /// <returns></returns>
        public FileInfo GetFileInfo(int? version = null)
        {
            var dir = GetDownloadDirectory();
            if (OptType == OfficeMiddlewareCore.OptType.查看正文 || OptType == OfficeMiddlewareCore.OptType.查看留痕正文 || OptType == OfficeMiddlewareCore.OptType.打开文档)
            {
                dir = Path.Combine(dir, "readonly");
            }
            var fileName = GetFileName(version);
            var fullPath = Path.Combine(dir, fileName);
            var fileInfo = new FileInfo(fullPath);
            return fileInfo;


        }
        static bool IsOccupied(string filePath)
        {
            var handler = _lopen(filePath, 2 | 0x40);
            CloseHandle(handler);
            return handler == new IntPtr(-1);
        }
        public bool IsOpen(int? version = null)
        {
            var file = GetFileInfo(version);
            if (file.Exists)
            {
                return IsOccupied(file.FullName);
            }
            else
            {
                return false;
            }
        }
        public bool IsExists(int? version = null)
        {
            var file = GetFileInfo(version);
            return file.Exists;
        }

        /// <summary>
        /// 获取本地备份文件
        /// </summary>
        /// <returns></returns>
        private FileInfo GetLocalBackupFile()
        {
            var dir = GetBackupFolder();

            var fullPath = Path.Combine(dir, GetFileName(GetDocVersion()));
            var fileInfo = new FileInfo(fullPath);
            return fileInfo;
        }

        /// <summary>
        /// 获取本地文档版本号
        /// </summary>
        /// <returns></returns>
        private int GetDocVersion()
        {
            var dir = GetDownloadDirectory();
            var downloadDirVersion = GetVersionByFolder(dir);
            return downloadDirVersion;

            int GetVersionByFolder(string folder)
            {
                var files = Directory.GetFiles(folder);
                if (files.Length == 0) return 0;
                var v = files.Where(w => Path.GetFileName(w).StartsWith($"{DocCode}")).Select(s =>
                {
                    var ext = Path.GetExtension(s);
                    var name = Path.GetFileName(s).Replace(ext, "").Split('_');
                    if (name.Length < 2) return 0;
                    int.TryParse(name[1], out var ver);
                    return ver;
                }).Distinct()
                  .OrderByDescending(o => o)
                  .FirstOrDefault();
                return v;
            }

        }
        private Tuple<Application, Document> _word;
        public void Upload()
        {
            _word.Item1.DocumentBeforeClose += _application_DocumentBeforeClose;

        }

        private void _application_DocumentBeforeClose(Document Doc, ref bool Cancel)
        {
            var localFileInfo = new FileInfo(LocalFileName);

            if (Doc.FullName != localFileInfo.FullName) return;
            try
            {
                Doc.Save();
            }
            catch (Exception ex)
            {
                LogHelper.Error("关闭文档，保存失败", ex);
            }
            UploadFile(localFileInfo.FullName);
            ThreadPool.QueueUserWorkItem(state =>
            {
                var file = state.ToString();
                try
                {
                    DeleteFile(file);
                }
                catch (Exception)
                {

                }
            }, localFileInfo.FullName);

        }
        private void DeleteFile(string file)
        {
            try
            {
                if (!File.Exists(file)) { return; }
                for (int i = 0; i < 10; i++)
                {
                    if (IsOccupied(file))
                    {
                        Thread.Sleep(500);
                    }
                    else
                    {
                        File.Delete(file);

                    }

                }
            }
            catch (System.IO.DirectoryNotFoundException ex)
            {

            }
        }
        private void UploadFile(string file)
        {
            var uploadFileInfo = new FileInfo(file);
            if (!uploadFileInfo.Exists) return;
            var tempFile = Path.Combine(Path.GetTempPath(), uploadFileInfo.Name);
            uploadFileInfo.CopyTo(tempFile);
            file = tempFile;
            ThreadPool.QueueUserWorkItem(state =>
            {
                var uploadFile = state.ToString();
                if (string.IsNullOrWhiteSpace(UploadPath)) return;
                if (File.Exists(uploadFile))
                {
                    var uploadAbort = true;
                    for (int i = 0; i < 3; i++)
                    {
                        if (HttpHelper.Instance.Upload(file, this))
                        {
                            DeleteFile(uploadFile);
                            uploadAbort = false;
                            break;
                        }
                        else
                        {
                            LogHelper.Error($"上传文件{uploadFile}失败,第{i + 1}次");
                            Thread.Sleep(500);
                        }
                    }

                    if (uploadAbort)
                    {
                        BackupFile(backFileName: uploadFile);
                        DeleteFile(uploadFile);
                        SendMessage(CoreResponseStatus.上传文件失败);
                        LogHelper.Error(message: "上传文件失败:" + uploadFile);
                    }
                }

            }, file);

        }

        public void Dispose()
        {
        }
    }
    public enum OptType
    {
        新建正文 = 0,
        处理正文 = 1,
        查看正文 = 2,
        清稿 = 3,
        合成格式 = 4,
        文件是否存在 = 5,
        文件是否打开 = 6,
        下载文件 = 7,
        打开Excel = 8,
        查看版本 = 9,
        打开文档 = 10,
        查看留痕正文 = 11,
        打开文件夹 = 12,
        检测Office安装情况 = 13
    }

    public enum OpenType
    {
        编辑模式打开,
        只读模式打开
    }
}
